// 发现在 Firefox 里面有 event 的问题。
var svgFontFamily = 'Times New Roman';
$(document).ready(function () {
    $('#pic-countsPerM').hide();

    $('#close-deep-insight').click(function () {
        $('#deep-insight').hide();
    });
    $('#close-dS-fa').click(function () {
        $('#dS-fa').hide();
    });
    $('#save-deep-insight-svg').click(function () {
        var svgxml = $('#deep-insight-svg').html();
        svgxml = '<?xml version="1.0" encoding="UTF-8" ?>' + "\n" + '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + svgxml;
        var blob = new Blob([svgxml], { type: 'image/svg+xml;charset=utf-8' });
        saveAs(blob, "deep-insight.svg");
    });

    var sizes = {}, offsets = {}, colors = {};
    // 试了再说
    var plot_ref = false;

    $('#plot-svg').click(function () {
        var k = $('#sid').val(),
            k1 = 'countsPerM', jobId = $('#job-id').text();

        $.getJSON('/b2dsc/handle_ajax', {
            jid: jobId, category: 'done',
            // keys: 'raw_id pIdent qCover filter_bls max_cnts ref_seq chromosome_length'
            // 不能从 done 里调取 pIdent, qCover，万一有人重新过滤了，就对不上了。
            keys: 'raw_id filter_bls max_cnts ref_seq chromosome_length'
        }, function (done) {
            // 需要读当前页面上的值
            // done.pIdent = +$('#current-pI').text(), done.qCover = +$('#current-qC').text();
            // done.pIqC = done.pIdent + '_' + done.qCover;
            // 比如 +'100.00' == 100，将会出现问题。
            done.pIqC = $('#current-pI').text() + '_' + $('#current-qC').text();
            $.getJSON(done.filter_bls[done.pIqC][k]['count'], function (d_cnts) {
                $('#id-' + k1).html(done.raw_id.qseq[k]);
                $('#sid-just-plotted').html(k);
                $('#svg-' + k1).html('');
                $('#pic-' + k1).show();
                if ($.isEmptyObject(d_cnts)) {
                    $('#utils-' + k1).addClass('hidden');
                    $('#svg-' + k1).html('<h1 class="emphasis">None</h1>');
                    return;
                } else {
                    $('a#count2tsv').attr('href',
                        '/b2dsc/count2tsv?jid=' + jobId +
                        '&sid=' + k + '&pIqC=' + done.pIqC
                    );
                    $('a#count2tsv').attr('target', '_blank');
                    $('#utils-' + k1).removeClass('hidden');
                    drawSVG(k, k1, done, d_cnts);
                }
            });
        });
    });

    function drawSVG(k, k1, done, d_cnts) {
        update_params4svg_plot();

        // 获取宽高
        var w = sizes.ruler.left + sizes.ruler.right + sizes.imageMargin.left + sizes.imageMargin.right,
            ws = {}, h = sizes.imageMargin.top,
            i = 0, genomes = [];
        for (var gn in d_cnts) {
            genomes[i] = gn;
            ++i;
            var wtmp = w;
            for (var hn in d_cnts[gn]) {
                wtmp += sizes.chr.left + sizes.chr.width + sizes.chr.right;
            }
            h += maxChrLen(gn, done, d_cnts) / 1e6 * sizes.pxPerMbp;

            if (i > 1) {
                h += sizes.betweenGenome;
            }
            ws[gn] = wtmp;
        }
        for (var gn in ws) {
            if (w < ws[gn]) {
                w = ws[gn];
            }
        }
        h += sizes.imageMargin.bottom; h = parseInt(h) + 1;
        genomes = genomes.sort();

        var svg = d3.select('#svg-' + k1).append('svg').attr('width', w).attr('height', h)
            .attr('xmlns', 'http://www.w3.org/2000/svg')
            .attr('xmlns:xlink', 'http://www.w3.org/1999/xlink')
            .attr('version', '1.1');

        var zoom = d3.zoom().scaleExtent([0.2, 20]).on("zoom", zoomed);

        var svgDefs = svg.append('defs');
        var legendId = 'legend' + parseInt(Math.random() * 100);
        colorLegend(svgDefs, legendId, done.max_cnts[done.pIqC][k]);

        // 背景
        var bgRect = svg.append('rect').attr('x', 0).attr('y', 0)
            .attr('width', w).attr('height', h)
            .attr('stroke', colors.bg).attr('fill', colors.bg);

        var container = svg.append('g');

        var xtg = sizes.imageMargin.left + sizes.ruler.left, ytg = sizes.imageMargin.top; // g - genome, t => translate
        for (var i in genomes) {
            var gn = genomes[i];
            var xt = xtg, yt = ytg;
            container.append('use').attr("xlink:href", "#" + legendId)
                .attr('x', sizes.legend.left).attr('y', yt);

            var rLen = maxChrLen(gn, done, d_cnts) / 1e6; // ruler length
            draw_ruler(container, gn, rLen, xt, yt);
            xt += sizes.ruler.right;
            for (var hn in d_cnts[gn]) {
                xt += sizes.chr.left;
                var g_chr = container.append('g').attr('id', 'chr' + hn + gn)
                    .attr('transform', 'translate(' + xt + ', ' + yt + ')');
                // 主染色体
                draw_chromosome(g_chr, gn, hn, done);
                // 分布 - ref
                draw_cnts_per_Mbp(g_chr, d_cnts, gn, hn, done.max_cnts[done.pIqC][k]);
                if (plot_ref) {
                    draw_refSeq_bars(g_chr, done.ref_seq, gn, hn);
                }

                xt += sizes.chr.width + sizes.chr.right;
            }
            ytg += rLen * sizes.pxPerMbp + sizes.betweenGenome;
        }

        d3.select('#utils-' + k1 + " > input.reset-svg").on("click", resetted);
        // 试试 zoom
        svg.call(zoom);

        function zoomed() {
            container.attr("transform", d3.event.transform);
        }

        function resetted() {
            svg.transition()
                .duration(750)
                .call(zoom.transform, d3.zoomIdentity);
        }
    }


    function legendGradient(svgDefs, id) {
        var gradient = svgDefs.append('linearGradient')
            .attr('id', id)
            .attr('x1', 0).attr('y1', 0)
            .attr('x2', 0).attr('y2', 1);

        gradient.append('stop').attr('offset', 0)
            .attr('stop-color', colors.lowerLimit.col);

        gradient.append('stop').attr('offset', 1)
            .attr('stop-color', colors.upperLimit.col);
    }

    function checkIntParam(id, defaultValue) {
        var val = parseInt($('#' + id).val());
        return isNaN(val) ? defaultValue : val;
    }

    function checkFloattParam(id, defaultValue) {
        var val = parseFloat($('#' + id).val());
        return isNaN(val) ? defaultValue : val;
    }

    // 设定了默认值
    function update_params4svg_plot() {
        sizes = {
            imageMargin: {
                top: checkIntParam('img-top', 60),
                bottom: checkIntParam('img-bottom', 50),
                left: checkIntParam('img-left', 0),
                right: checkIntParam('img-right', 10)
            },
            pxPerMbp: checkIntParam('px-per-Mbp', 1),
            legend: {
                left: checkIntParam('legend-left', 20),
                tickLength: checkIntParam('legend-tick-length', 8),
                length: checkIntParam('legend-length', 100),
                width: checkIntParam('legend-width', 10)
            },
            ruler: {
                left: checkIntParam('ruler-left', 150),
                right: checkIntParam('ruler-right', 50),
                tickLength: checkIntParam('ruler-tick-length', 10)
            },
            chr: {
                left: checkIntParam('chr-left', 50),
                right: checkIntParam('chr-right', 50),
                width: checkIntParam('chr-width', 30),
                capRadius: checkIntParam('chr-cap-radius', 0)
            },
            betweenGenome: checkIntParam('between-genome', 150),
            font: {
                tickLabel: checkIntParam('fsize-tick', 12),
                Mbp: checkIntParam('fsize-Mbp', 16),
                chrName: checkIntParam('fsize-chrName', 20)
            },
            bars: {
                width: checkIntParam('bar-width', 40),
                toChr: checkIntParam('bar2chr-width', 10)
            }
        };
        // 需要在 sizes 之后
        offsets = {
            legendTickLabel: {
                x: checkIntParam('legend-tick-label-x', 5),
                // 改为 em
                y: checkFloattParam('legend-tick-label-y', 0.35) * sizes.font.tickLabel
            },
            rulerTickLabel: {
                x: checkIntParam('ruler-tick-label-x', -5),
                // 改为 em
                y: checkFloattParam('ruler-tick-label-y', 0.35) * sizes.font.tickLabel
            },
            Mbp: {
                x: 0,
                y: checkFloattParam('mbp-y', 1.5) * sizes.font.Mbp
            },
            chrName: {
                x: sizes.chr.width / 2,
                y: checkFloattParam('chrName-y', -0.75) * sizes.font.chrName
            }
        };
        colors = {
            bg: $('#bg-color').val() || '#000',
            fg: $('#fg-color').val() || '#fff',
            chr: {
                fill: $('#chr-fill').val() || 'rgb(0, 0, 139)',
                stroke: $('#chr-stroke').val() || 'rgb(0, 0, 139)'
            },
            lowerLimit: {
                val: checkIntParam('lower-limit', 0),
                col: $('#lower-limit-color').val() || 'rgb(0, 0, 255)'
            },
            upperLimit: {
                val: checkIntParam('upper-limit', 100),
                col: $('#upper-limit-color').val() || 'rgb(255, 0, 0)'
            },
            gradientSteps: checkIntParam('steps', 1)
        };

        if ($('#refSeq').is(':checked')) {
            plot_ref = true;
        } else {
            plot_ref = false;
        }
    }

    // 似乎有 d3.color 可用
    function color4value(frgb, trgb, steps, fv, tv, v) {
        steps = parseInt(steps);
        frgb = getRGB(frgb);
        trgb = getRGB(trgb);
        var v_rgb;
        if (steps > 1) {
            v_rgb = [
                frgb['r'] + parseInt(
                    (v - fv) / ((tv - fv) / steps) * ((trgb['r'] - frgb['r']) / steps)
                ),
                frgb['g'] + parseInt(
                    (v - fv) / ((tv - fv) / steps) * ((trgb['g'] - frgb['g']) / steps)
                ),
                frgb['b'] + parseInt(
                    (v - fv) / ((tv - fv) / steps) * ((trgb['b'] - frgb['b']) / steps)
                )
            ];
        } else {
            v_rgb = [trgb['r'], trgb['g'], trgb['b']];
        }

        return 'rgb(' + v_rgb.join(', ') + ')';
    }

    function getRGB(rgb) {
        var rRgba = /rgba?\((\d{1,3}),(\d{1,3}),(\d{1,3})(,([.\d]+))?\)/,
            r, g, b, a,
            rsa = rgb.replace(/\s+/g, "").match(rRgba);
        if (rsa) {
            r = +rsa[1];
            g = +rsa[2];
            b = +rsa[3];
            a = +rsa[5];
            return { r: r, g: g, b: b };
        } else {
            return rgb;
        }
    }

    function maxChrLen(genome, done, d_cnts) {
        var maxLen = 0;
        // 注意这里 hg => 1,2,3,...
        for (var hg in d_cnts[genome]) {
            var cLen = done.chromosome_length[genome][hg - 1];
            if (cLen > maxLen) {
                maxLen = cLen;
            }
        }
        return maxLen;
    }

    function colorLegend(svgDefs, id, max_cnt_of_qseq) {
        var id_gradient = id + 'LGradient';
        legendGradient(svgDefs, id_gradient);

        var legend = svgDefs.append('g').attr('id', id);

        var len = sizes.legend.length;
        var len_flank = 50; // 0 -> lowerLimit, upperLimit -> max_cnt
        var w = sizes.legend.width, tick_len = sizes.legend.tickLength;
        var w_flank = w / 2;
        var x2_tick = w + tick_len;
        var y = 0;
        var dTicks = [], dRects = [];

        // 0 -> lower-limit
        if (colors.lowerLimit.val > 0) {
            dTicks.push({ 'y': y, 'text': '0' });
            dRects.push({ 'w': w_flank, 'h': len_flank, 'x': w_flank, 'y': y, 'fill': colors.chr.fill });
            y += len_flank;
        }
        // main legend
        dTicks.push(
            { 'y': y, 'text': '' + colors.lowerLimit.val },
            { 'y': y + len / 2, 'text': '' + (colors.lowerLimit.val + colors.upperLimit.val) / 2 },
            { 'y': y + len, 'text': '' + colors.upperLimit.val }
        );
        dRects.push({ 'w': w, 'h': len, 'x': 0, 'y': y, 'fill': 'url(#' + id_gradient + ')' });
        y += len;
        // upper-limit -> max-cnt
        if (colors.upperLimit.val < max_cnt_of_qseq) {
            dTicks.push({ 'y': y + len_flank, 'text': '' + max_cnt_of_qseq });
            dRects.push({ 'w': w_flank, 'h': len_flank, 'x': w_flank, 'y': y, 'fill': colors.upperLimit.col });
        }

        legend.selectAll('rect').data(dRects).enter().append('rect')
            .attr('width', function (d) { return d.w })
            .attr('height', function (d) { return d.h })
            .attr('x', function (d) { return d.x }).attr('y', function (d) { return d.y })
            .attr('fill', function (d) { return d.fill });

        legend.selectAll('line').data(dTicks).enter().append('line')
            .attr('x1', w).attr('y1', function (d) {
                return d.y;
            }).attr('x2', x2_tick).attr('y2', function (d) {
                return d.y;
            }).attr('stroke', colors.fg);

        var tickLabels = legend.selectAll('text').data(dTicks).enter().append('text')
            .attr('x', x2_tick + offsets.legendTickLabel.x)
            .attr('y', function (d) { return d.y })
            .attr('dy', offsets.legendTickLabel.y)
            .text(function (d) { return d.text })
            .attr('font-family', svgFontFamily)
            .attr('font-size', sizes.font.tickLabel + 'px')
            .attr('fill', colors.fg);
    }

    function draw_ruler(svg, genome, rLen, xt, yt) {
        rLen = parseInt(rLen) + 1;
        var rLenPx = rLen * sizes.pxPerMbp;

        var g_ruler = svg.append('g').attr('id', 'ruler_' + genome)
            .attr('transform', 'translate(' + xt + ', ' + yt + ')')
            .attr('stroke', colors.fg);
        var g_labels = svg.append('g').attr('id', 'ruler_labels_' + genome)
            .attr('transform', 'translate(' + xt + ', ' + yt + ')')
            .attr('fill', colors.fg);

        var dLines = [], dTexts = []; // d - data

        // 主轴
        dLines.push({ x1: 0, y1: 0, x2: 0, y2: rLenPx });
        // ticks
        var tick_unit = (rLen >= 100) ? 10 : 1; // >= 100 Mbp, 10; < 100 Mbp, 1
        for (var y = 0; y <= rLen; y += tick_unit) {
            var x1, y1 = y * sizes.pxPerMbp;
            if (y % (10 * tick_unit) === 0) {
                x1 = -sizes.ruler.tickLength;
                dTexts.push({
                    text: '' + y,
                    x: x1 + offsets.rulerTickLabel.x, y: y1,
                    dy: offsets.rulerTickLabel.y,
                    size: sizes.font.tickLabel + 'px', anchor: 'end'
                });
            } else if (y % (5 * tick_unit) === 0) {
                x1 = -3 / 4 * sizes.ruler.tickLength;
            } else {
                x1 = -1 / 2 * sizes.ruler.tickLength;
            }
            dLines.push({ x1: x1, y1: y1, x2: 0, y2: y1 });
        }
        // Mbp
        dTexts.push({
            text: 'Mbp',
            x: offsets.Mbp.x, y: rLenPx,
            dy: offsets.Mbp.y,
            size: sizes.font.Mbp + 'px', anchor: 'middle'
        });

        g_ruler.selectAll('line').data(dLines).enter().append('line')
            .attr('x1', function (d) { return d.x1 }).attr('y1', function (d) { return d.y1 })
            .attr('x2', function (d) { return d.x2 }).attr('y2', function (d) { return d.y2 });

        g_labels.selectAll('text').data(dTexts).enter().append('text')
            .attr('x', function (d) { return d.x }).attr('y', function (d) { return d.y })
            .attr('dy', function (d) { return d.dy })
            .text(function (d) { return d.text })
            .attr('font-family', svgFontFamily)
            .attr('font-size', function (d) { return d.size })
            .attr('text-anchor', function (d) { return d.anchor });
    }

    function draw_chromosome(dgrp, genome, hgrp, done) {
        var chromosome_length = done.chromosome_length;
        var cLen = chromosome_length[genome][hgrp - 1] / 1e6 * sizes.pxPerMbp;
        var capRad = sizes.chr.capRadius;
        dgrp.append('rect').attr('x', 0).attr('y', -capRad)
            .attr('width', sizes.chr.width).attr('height', cLen + capRad * 2)
            .attr('rx', capRad).attr('ry', capRad)
            .attr('stroke', colors.chr.stroke).attr('fill', colors.chr.fill);
        dgrp.append('text').attr('x', offsets.chrName.x)
            .attr('y', -capRad)
            .attr('dy', offsets.chrName.y)
            .text(hgrp + genome)
            .attr('font-family', svgFontFamily).attr('font-size', sizes.font.chrName + 'px')
            .attr('text-anchor', 'middle').attr('fill', colors.fg);
    }

    function draw_cnts_per_Mbp(dgrp, d_cnts, genome, hgrp, max_cnt_of_qseq) {
        var steps = colors.gradientSteps, chrName = hgrp + genome;
        var d_chr_cnts = d_cnts[genome][hgrp];
        for (var pos in d_chr_cnts) {
            var cnt = d_chr_cnts[pos];
            if (cnt < colors.lowerLimit.val) continue;
            var col = '';
            if (cnt < colors.upperLimit.val) {
                col = color4value(
                    colors.lowerLimit.col,
                    colors.upperLimit.col,
                    steps,
                    colors.lowerLimit.val,
                    colors.upperLimit.val,
                    cnt
                );
            } else {
                col = colors.upperLimit.col;
            }
            var pos_1 = (+pos + 0.5) * sizes.pxPerMbp;
            // 染色体上横线
            dgrp.append('line')
                .attr('id', ['qseqL', chrName, pos, cnt].join('-'))
                .attr('class', 'clickable')
                .attr('x1', 1).attr('y1', pos_1)
                .attr('x2', sizes.chr.width - 1).attr('y2', pos_1)
                .attr('stroke', col).attr('stroke-width', sizes.pxPerMbp)
                .on('mouseover', svg_mouseover_id).on('mouseout', function () {
                    $('#tooltip').empty().hide();
                }).on('click', svg_click_id);
            // bar
            if (sizes.bars.width > 0) {
                var x_rbar = sizes.chr.width + sizes.bars.toChr;
                dgrp.append('line')
                    .attr('id', ['qseqB', chrName, pos, cnt].join('-'))
                    .attr('class', 'clickable')
                    .attr('x1', x_rbar).attr('y1', pos_1)
                    .attr('x2', x_rbar + cnt / max_cnt_of_qseq * sizes.bars.width)
                    .attr('y2', pos_1)
                    .attr('stroke', col).attr('stroke-width', sizes.pxPerMbp)
                    .on('mouseover', svg_mouseover_id).on('mouseout', function () {
                        $('#tooltip').empty().hide();
                    }).on('click', svg_click_id);
            }
        }
    }

    function draw_refSeq_bars(dgrp, refSeq, genome, hgrp) {
        var rid = refSeq.id, rJid = refSeq.jid, pIqC = refSeq.pident + '_' + refSeq.qcovhsp;
        var col = $('#color-refSeq').val() || 'rgb(190, 190, 190)';

        $.getJSON('/b2dsc/handle_ajax', {
            jid: rJid, category: 'done',
            keys: 'filter_bls max_cnts'
        }, function (done) {
            $.getJSON(done.filter_bls[pIqC][rid]['count'], function (d_cnts) {
                var max_cnt_of_refSeq = done.max_cnts[pIqC][rid];
                var d_chr_cnts = d_cnts[genome][hgrp];

                // draw_cnts_per_Mbp() 大概不需要下面这句
                if (d_chr_cnts == 'undefined') return;

                for (var pos in d_chr_cnts) {
                    var cnt = d_chr_cnts[pos];
                    var pos_1 = (+pos + 0.5) * sizes.pxPerMbp;

                    if (sizes.bars.width > 0) {
                        var x_lbar = -sizes.bars.toChr;
                        dgrp.append('line')
                            .attr('id', ['refSeqB', hgrp + genome, pos, cnt].join('-'))
                            .attr('x1', x_lbar).attr('y1', pos_1)
                            .attr('x2', x_lbar - cnt / max_cnt_of_refSeq * sizes.bars.width)
                            .attr('y2', pos_1)
                            .attr('stroke', col).attr('stroke-width', sizes.pxPerMbp)
                            .on('mouseover', svg_mouseover_id).on('mouseout', function () {
                                $('#tooltip').empty().hide();
                            });
                    }
                }
            });
        });
    }

    // 原来是 legend 可以这样，rect 不可以。
    function svg_mouseover_id(event) {
        var event = event ? event : (window.event || d3.event);
        var tar = event.srcElement || event.target;
        var lid = tar.id;
        var type_chr_pos_cnt = lid.split('-');
        var tp = type_chr_pos_cnt[0], chrName = type_chr_pos_cnt[1],
            pos = parseInt(type_chr_pos_cnt[2]), pos_1 = pos + 1,
            cnt = type_chr_pos_cnt[3];

        var mousePos = {
            x: event.pageX,
            y: event.pageY
        };
        var xOffset = 20, yOffset = 25;
        var tip = chrName + '<br>' + 'position: ' + pos + '–' + pos_1 + ' Mbp<br>' + 'Number of repeats: ' + cnt;
        if (tp.match(/^qseq/)) {
            tip += '<br><br><i>Click it to view details.</i>';
        }
        $('#tooltip').show().css({
            // 'position': 'absolute',
            'top': (mousePos.y - yOffset) + 'px',
            'left': (mousePos.x + xOffset) + 'px'
            // }).html(type_chr_pos_cnt[1] + '<br>' + 'position: ' +  + '–' + type_chr_pos_cnt[2] + '<br>' + 'counts: ' + type_chr_pos_cnt[3]);
        }).html(tip);
    }

    function svg_click_id(event) {
        var event = event ? event : (window.event || d3.event);
        var tar = event.srcElement || event.target;
        var lid = tar.id;
        var type_chr_pos_cnt = lid.split('-');
        var chr = type_chr_pos_cnt[1], pos = type_chr_pos_cnt[2], cnt = type_chr_pos_cnt[3];

        deep_insight($('#sid').val(), chr, pos, cnt);
    }
});